package core

import "fmt"

// 定义一些AOI的边界值
const (
	AOI_MIN_X  int = 0
	AOI_MAX_X  int = 250
	AOI_CNTS_X int = 5
	AOI_MIN_Y  int = 0
	AOI_MAX_Y  int = 250
	AOI_CNTS_Y int = 5
)

/*
	AOI区域管理模块
*/

type AOIManage struct {
	// 区域左边边界坐标
	MinX int
	// 区域右边边界坐标
	MaxX int
	// X方向格子的数量
	CntsX int
	// 区域上边边界坐标
	MinY int
	// 区域下边边界坐标
	MaxY int
	// Y方向格子的数量
	CntsY int
	// 当前区域有哪些格子map-key=格子的ID，value=格子对象
	grids map[int]*Grid
}

/*
	初始化一个AOI区域管理模块
*/
func NewAOIManager(minX, maxX, cntsX, minY, maxY, cntsY int) *AOIManage {
	aoiMgr := &AOIManage{
		MinX:  minX,
		MaxX:  maxX,
		CntsX: cntsX,
		MinY:  minY,
		MaxY:  maxY,
		CntsY: cntsY,
		grids: make(map[int]*Grid),
	}

	// 给AOI初始化区域的格子所有的格子进行编号 和 初始化
	for y := 0; y < cntsY; y++ {
		for x := 0; x < cntsX; x++ {
			// 计算格子ID 根据x，y编号
			// 格子编号：id = idY * cntX + idX
			gid := y*cntsX + x
			// 初始化gid格子
			aoiMgr.grids[gid] = NewGrid(gid,
				aoiMgr.MinX+x*aoiMgr.gridWidth(),
				aoiMgr.MinX+(x+1)*aoiMgr.gridWidth(),
				aoiMgr.MinY+y*aoiMgr.gridLength(),
				aoiMgr.MinY+(y+1)*aoiMgr.gridLength(),
			)
		}
	}

	return aoiMgr
}

// 得到每个格子在X轴方向的宽度
func (m *AOIManage) gridWidth() int {
	return (m.MaxX - m.MinX) / m.CntsX
}

// 得到每个格子在Y轴方向的高度
func (m *AOIManage) gridLength() int {
	return (m.MaxY - m.MinY) / m.CntsY
}

// 打印格子的信息
func (m *AOIManage) String() string {
	// 打印AOIManage信息
	str := fmt.Sprintf("AOIManage:\nminX:%d, maxX:%d, cntsX:%d, minY:%d, maxY:%d, cntsY:%d",
		m.MinX, m.MaxX, m.CntsX, m.MinY, m.MaxY, m.CntsY)

	for _, grid := range m.grids {
		str += fmt.Sprintln(grid)
	}

	return str
}

// 根据格子GID得到周围九宫格的格子集合
func (m *AOIManage) GetSurroundGridsByGID(gID int) (grids []*Grid) {
	// 判断gID是否在AOIManage中
	if _, ok := m.grids[gID]; !ok {
		return
	}

	// 初始化grids返回值切片 将当前gid本身放在九宫格切片中
	grids = append(grids, m.grids[gID])

	// 需要判断gID的左边和右边是否有格子 需要通过gID得到当前钩子x轴的编号 --idx=id % nx
	idx := gID % m.CntsX

	// 判断idx左边是否有格子，如果有 放在gidsX集合中
	if idx > 0 {
		grids = append(grids, m.grids[gID-1])
	}

	// 判断idx右边是否还有格子，如果有 放在gidsX集合中
	if idx < m.CntsX-1 {
		grids = append(grids, m.grids[gID+1])
	}
	// 将x轴当前的格子都取出，进行遍历，再分别得到每个格子的上下是否还有格子
	// 得到当前gidsX中的每个格子
	gidsX := make([]int, 0, len(grids))
	for _, v := range grids {
		gidsX = append(gidsX, v.GID)
	}
	fmt.Println("gidsX Length: ", len(gidsX))

	// 遍历gidsX集合中每个格子的gid
	for _, v := range gidsX {
		idy := v / m.CntsY
		// gid上面是否有格子
		if idy > 0 {
			grids = append(grids, m.grids[v-m.CntsX])
		}
		// gid下面是否有格子
		if idy < m.CntsY-1 {
			grids = append(grids, m.grids[v+m.CntsX])
		}
	}
	return
}

// 通过横纵坐标得到当前GID格子编号
func (m *AOIManage) GetGidByPos(x, y float32) int {
	idx := (int(x) - m.MinX) / m.gridWidth()
	idy := (int(y) - m.MinY) / m.gridLength()
	return idy*m.CntsX + idx
}

// 通过横纵坐标得到周围九宫格内全部的PlayerIDs
func (m *AOIManage) GetPidsByPos(x, y float32) (playerIDs []int) {
	// 得到当前玩家的GID格子id
	gID := m.GetGidByPos(x, y)

	// 通过gID得到周边九宫格内全部的PlayerIDs
	grids := m.GetSurroundGridsByGID(gID)

	// 将九宫格的信息里的全部的Player的id 累加到playerIDs
	for _, grid := range grids {
		playerIDs = append(playerIDs, grid.GetPlayerIDs()...)
		fmt.Printf("===> grid ID %d,pids:%v", grid.GID, grid.GetPlayerIDs())
	}
	return
}

// 添加一个PlayerID到一个格子中
func (m *AOIManage) AddPidToGrid(pID, gID int) {
	m.grids[gID].Add(pID)
}

// 移除一个格子中的PlayerID
func (m *AOIManage) RemovePidFromGrid(pID, gID int) {
	m.grids[gID].Remove(pID)
}

// 通过GID获取全部的PlayerID
func (m *AOIManage) GetPidByGid(gID int) (playerIDs []int) {
	playerIDs = m.grids[gID].GetPlayerIDs()
	return
}

// 通过坐标将Player添加到一个格子中
func (m *AOIManage) AddToGridByPos(pID int, x, y float32) {
	gID := m.GetGidByPos(x, y)
	grid := m.grids[gID]
	grid.Add(pID)
}

// 通过坐标把一个Player从一个格子中删除
func (m *AOIManage) RemoveFromGridByPos(pID int, x, y float32) {
	gID := m.GetGidByPos(x, y)
	grid := m.grids[gID]
	grid.Remove(pID)
}
